/*
 * Copyright (C) 2022, KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

//
// Created by hxf on 22-7-28.
//

#include "shortcut-model.h"

#include <QIcon>
#include <QDebug>

using namespace UkuiShortcut;

ShortcutModel::ShortcutModel(PluginMetaType::SystemMode mode, QObject *parent) : QAbstractListModel(parent), m_currentMode(mode)
{

}

bool ShortcutModel::insertShortcut(Shortcut *shortcut)
{
    if (!shortcut) {
        return false;
    }
    if (m_shortcuts.contains(shortcut)) {
        return false;
    }

    m_shortcuts.append(shortcut);
    m_statusInfos.insert(shortcut, shortcut->currentStatus());
    shortcut->disconnect(this);
    connect(shortcut, &Shortcut::statusChanged, this, [this, shortcut] (const StatusInfo &info) {
        this->updateShortcutStatus(shortcut, info);
    });

    sortAllShortCuts(m_shortcuts, m_currentMode);

    ++m_shortcutCount;
    beginResetModel();
    endResetModel();
    return true;
}

bool ShortcutModel::removeShortcut(Shortcut *shortcut)
{
    if (!shortcut) {
        return false;
    }

    int index = m_shortcuts.indexOf(shortcut);
    if (index == -1) {
        return false;
    }

    shortcut->disconnect(this);
    beginRemoveRows(QModelIndex(), index, index);
    m_shortcuts.removeAt(index);
    m_statusInfos.remove(shortcut);
    --m_shortcutCount;
    endRemoveRows();
    return true;
}

int ShortcutModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_shortcutCount;
}

QVariant ShortcutModel::data(const QModelIndex &index, int role) const
{
    int row = index.row();
    if (row < 0 || row >= m_shortcutCount) {
        return {};
    }

    StatusInfo statusInfo = m_statusInfos.value(m_shortcuts.at(row));
    switch (role) {
        case ValueType::Disabled: {
            return statusInfo.isDisabled();
        }
        case ValueType::Name: {
            return statusInfo.getName();
        }
        case ValueType::Icon: {
            return statusInfo.getIcon();
        }
        case ValueType::ToolTip: {
            return statusInfo.getToolTip();
        }
        case ValueType::Color: {
            return statusInfo.getColor();
        }
        case ValueType::Value: {
            return statusInfo.getValue();
        }
        case ValueType::Menu: {
            return QVariant::fromValue<QList<UkuiShortcut::StatusInfo::MenuItem> >(statusInfo.getMenu());
        }
        default:
            break;
    }

    return {};
}

void ShortcutModel::updateShortcutStatus(Shortcut* plugin, const StatusInfo &info)
{
    if (!plugin) {
        return;
    }

    int pluginIndex = m_shortcuts.indexOf(plugin);
    if (pluginIndex == -1) {
        return;
    }

    //获取哪些属性发生了变化，小范围更新
    QVector<int> roles(0);
    compareDataChanges(roles, m_statusInfos.value(plugin), info);
    if (roles.empty()) {
        return;
    }

    // 更新model数据
    m_statusInfos.insert(plugin, info);
    // 前端在拖动进度条时，屏蔽插件的value更新，不发送dataChanged信号
    if (m_disableValueUpdate && roles.contains(ValueType::Value)) {
        roles.remove(roles.indexOf(ValueType::Value));
        if (roles.empty()) {
            return;
        }
    }

    QModelIndex current = index(pluginIndex, 0);
    Q_EMIT dataChanged(current, current, roles);
}

QHash<int, QByteArray> ShortcutModel::roleNames() const
{
    QHash<int, QByteArray> names;
    names.insert(ValueType::Disabled, "disabled");
    names.insert(ValueType::Name, "name");
    names.insert(ValueType::Icon, "icon");
    names.insert(ValueType::ToolTip, "tooltip");
    names.insert(ValueType::Color, "color");
    names.insert(ValueType::Value, "value");
    names.insert(ValueType::Menu, "menu");
    return names;
}

void ShortcutModel::active(int index, PluginMetaType::Action action)
{
    if (index < 0 || index >= m_shortcuts.size()) {
        return;
    }

    Shortcut *shortcut = m_shortcuts.at(index);
    execPreAction(shortcut);
    shortcut->active(action);
}

void ShortcutModel::setValue(int index, const int value)
{
    //判断边界
    if (index < 0 || index >= m_shortcuts.size()) {
        return;
    }

    Shortcut *shortcut = m_shortcuts.at(index);
    shortcut->setValue(value);
}

void ShortcutModel::compareDataChanges(QVector<int> &roles, const StatusInfo &infoA, const StatusInfo &infoB) const
{
    if (infoA.getName() != infoB.getName()) {
        roles.append(ValueType::Name);
    }

    if (infoA.getColor() != infoB.getColor()) {
        roles.append(ValueType::Color);
    }

    if (infoA.getToolTip() != infoB.getToolTip()) {
        roles.append(ValueType::ToolTip);
    }

    if (infoA.getIcon() != infoB.getIcon()) {
        roles.append(ValueType::Icon);
    }

    if (infoA.isDisabled() != infoB.isDisabled()) {
        roles.append(ValueType::Disabled);
    }

    if (infoA.getValue() != infoB.getValue()) {
        roles.append(ValueType::Value);
    }
}

void ShortcutModel::disableValueUpdate(bool disable)
{
    m_disableValueUpdate = disable;
}

void ShortcutModel::setCurrentMode(PluginMetaType::SystemMode newMode)
{
    m_currentMode = newMode;
    updateModel();
}

void ShortcutModel::sortAllShortCuts(QList<Shortcut*> &shortcuts, PluginMetaType::SystemMode currentMode)
{
//    if (shortcuts.empty()) {
//        return;
//    }

    std::sort(shortcuts.begin(), shortcuts.end(), [=] (Shortcut *s1, Shortcut *s2) {
        int indexS1 = s1->pluginMetaData().value(currentMode).index();
        int indexS2 = s2->pluginMetaData().value(currentMode).index();

        if ((indexS1 != -1) && (indexS2 != -1)) {
            return  indexS2 > indexS1;
        }
        else if (indexS2 == -1) {
            return true;
        }
        else {
            return false;
        }
    });
}

void ShortcutModel::updateModel()
{
    // 切换系统模式后，从新排序界面组件
    sortAllShortCuts(m_shortcuts, m_currentMode);
    beginResetModel();
    endResetModel();
}

void ShortcutModel::execPreAction(Shortcut *shortcut)
{
    PluginMetaType::PredefinedAction preAction = shortcut->pluginMetaData().value(m_currentMode).preAction();
    if (preAction != PluginMetaType::NoAction) {
        Q_EMIT requestExecAction(preAction);
    }
}
